#include "napi/native_api.h"
#include <bits/alltypes.h>
#include <stdio.h>
#include <stdlib.h>
#include "hilog/log.h"

#include "fftw3.h"

static napi_value Add(napi_env env, napi_callback_info info)
{
    size_t requireArgc = 2;
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);

    return sum;

}

double in_data[10000];

#if 1
static napi_value Arkts_fftw_plan_dft_r2c_1d(napi_env env, napi_callback_info info) {
    // 获取TS层传来的参数
    //OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "Arkts_fftw_plan_dft_r2c_1d:");

    // HiLog.warn(LABEL, "Failed to visit , reason:.");
    size_t argc = 1;
    napi_value args;
    napi_get_cb_info(env, info, &argc, &args, NULL, NULL);
    napi_value input_array = args;

    int32_t infoTypeParam;
    // napi_get_value_int32(env, args[1], &infoTypeParam);

    // 获取传入数组typedarray生成input_buffer
    napi_typedarray_type type; // 数据类型
    napi_value input_buffer;
    size_t byte_offset; // 数据偏移
    size_t i, length;   // 数据字节大小
    void *data;
    napi_get_typedarray_info(env, input_array, &type, &length, NULL, &input_buffer, &byte_offset);

    // 获取数组数据

    size_t byte_length;
    napi_get_arraybuffer_info(env, input_buffer, &data, &byte_length);

    // 遍历数组

    double *data_bytes = (double *)(data);
    OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "input convert begin");
    for (i = 0; i < length / sizeof(double); i++) {
        in_data[i] = *((double *)(data_bytes) + i);

        //OH_LOG_INFO(LOG_APP, "TS2NAPI: C++  %{public}lf", *((double *)(data_bytes) + i));
    }

    OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "input convert end");

    int size = i;

    fftw_plan p_fft;

    OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "begin fftw");

    fftw_complex *outDftCpx = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * size);

    OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "begin fftw1");

    p_fft = fftw_plan_dft_r2c_1d(size, in_data, outDftCpx, FFTW_ESTIMATE);

    OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "begin fftw2");

    fftw_execute(p_fft);

    OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "begin fftw3");
    // fftw_execute(p_ifft);
    // get_time();

    fftw_destroy_plan(p_fft);

    OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "end fftw");


    napi_value output_buffer;
    void *output_ptr = NULL;
    napi_create_arraybuffer(env, size * 8 * 2, &output_ptr, &output_buffer);

    napi_value output_array;

    napi_create_typedarray(env, napi_float64_array, size * 2, output_buffer, 0, &output_array);

    double *output_doubles = (double *)(output_ptr);

  //  OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "out convert begin");
    for (i = 0; i < size; i++) {
        output_doubles[i * 2] = outDftCpx[i][0];

        output_doubles[i * 2 + 1] = outDftCpx[i][1];
    }

 //   OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "out convert begin");

    fftw_free(outDftCpx);
/*
    for (int i = 0; i < size; i++) {
        OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "R2C_DFT[%{public}d]: Re= %{public}lf，Im(j)= %{public}lf:", i,
                     outDftCpx[i][0], outDftCpx[i][1]);
    }
*/
    return output_array;
}

    #endif
    
#if 0
static napi_value Arkts_fftw_plan_dft_r2c_1d(napi_env env, napi_callback_info info) {
    // 获取TS层传来的参数
    OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "Arkts_fftw_plan_dft_r2c_1d:");

    //HiLog.warn(LABEL, "Failed to visit , reason:.");
    size_t argc = 1;
    napi_value args;
    napi_get_cb_info(env, info, &argc, &args, NULL, NULL);
    napi_value input_array = args;

    int32_t infoTypeParam;
    //napi_get_value_int32(env, args[1], &infoTypeParam);
    
    // 获取传入数组typedarray生成input_buffer
    napi_typedarray_type type; // 数据类型
    napi_value input_buffer;
    size_t byte_offset; // 数据偏移
    size_t i, length;   // 数据字节大小
    void *data;
    napi_get_typedarray_info(env, input_array, &type, &length, NULL, &input_buffer, &byte_offset);

        // 获取数组数据
        
    size_t byte_length;
    napi_get_arraybuffer_info(env, input_buffer, &data, &byte_length);
   
    // 遍历数组
        
    double *data_bytes = (double *)(data);
    for (i = 0; i < length / sizeof(double); i++) {
        in_data[i] = *((double *)(data_bytes) + i);
            
        OH_LOG_INFO(LOG_APP, "TS2NAPI: C++  %{public}lf", *((double *)(data_bytes) + i));
    }
    
    int size = i;
    
    fftw_plan p_fft;

    fftw_complex *outDftCpx = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * size);

    p_fft = fftw_plan_dft_r2c_1d(size, in_data, outDftCpx, FFTW_ESTIMATE);
    
    fftw_execute(p_fft);
        // fftw_execute(p_ifft);
        // get_time();

    fftw_destroy_plan(p_fft);
    


    napi_value output_buffer;
    void *output_ptr = NULL;
    napi_create_arraybuffer(env, size * 8 * 2, &output_ptr, &output_buffer);

    napi_value output_array;
    
    napi_create_typedarray(env, napi_float64_array, size * 2, output_buffer, 0, &output_array);

    double *output_doubles = (double *)(output_ptr);
    for (i = 0; i < size; i++) {
        output_doubles[i * 2] = outDftCpx[i][0];

        output_doubles[i * 2 + 1] = outDftCpx[i][1];
    }

    fftw_free(outDftCpx);
/*
    for (int i = 0; i < size; i++) {
        OH_LOG_Print(LOG_APP, LOG_DEBUG, 0xff00, "fftw", "R2C_DFT[%{public}d]: Re= %{public}lf，Im(j)= %{public}lf:", i, outDftCpx[i][0],
                     outDftCpx[i][1]);
    }
  */  
    return output_array;
}

#endif

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
                                       {"arkts_fftw_plan_dft_r2c_1d", nullptr, Arkts_fftw_plan_dft_r2c_1d, nullptr,
                                        nullptr, nullptr, napi_default, nullptr}
                                    

    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "fftwlib",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterFftwlibModule(void)
{
    napi_module_register(&demoModule);
}
